package tool.soft

import java.io.File
import akka.stream.Materializer
import akka.stream.scaladsl.Sink
import akka.util.ByteString
import dao._
import implicits.Implicits._
import models.Tables
import models.Tables._
import org.joda.time.DateTime
import org.zeroturnaround.zip.ZipUtil
import play.api.data.FormBinding
import play.api.libs.ws.WSClient
import play.api.mvc.{AnyContent, Request}
import play.twirl.api.Html
import shared.Pojo._
import tool.Pojo._
import tool.plot.AllPlot._
import tool.soft.AllSoft.SoftBT
import tool._
import utils.Utils

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.language.postfixOps
import play.api.i18n.Messages
import upickle.default._

/**
 * Created by yz on 15/9/2020
 */
object IPathSoft extends IPathSoftT with SoftBT {

  override def getFileInfos(workspaceDir: File, index: Int)(implicit matrixFileDataDao: MatrixFileDataDao, messages: Messages): List[FileInfoData] = {
    List(
      FileInfoData("iPath3.svg", messages("iPath3")),
    )
  }

  override def produceConfigFile(workspaceDir: File, index: Int)(implicit request: Request[AnyContent], formBinding: FormBinding) = {
    Utils.t2ConfigFile(data, Tool.getCalculateConfigJsonFile(workspaceDir))
    Utils.t2ConfigFile(workspaceDir, data)
  }

  override def getResultHtml(missionId: Int)(implicit request: Request[AnyContent], messages: Messages): Html = {
    views.html.user.mission.iPathResult(missionId)
  }

  def getArg(implicit request: Request[AnyContent], messages: Messages, formBinding: FormBinding): ujson.Value = {
    val basicJson = ujson.Obj()
    val fcJson = if (data.hasGroup.isDefined) {
      val groupNum = Tool.getGroupNum(userId, data.groupFile)
      groupNum match {
        case x if x == 2 => ujson.Obj(messages("fCCalculationMethod") -> Tool.getFcMethod(data.fcMethod))
        case x => ujson.Obj()
      }
    } else {
      ujson.Obj()
    }
    basicJson ++ fcJson
  }

  override def resultDeal(workspaceDir: File, resultDir: File)(implicit ws: WSClient, materializer: Materializer): Unit = {
    val f = stepIPath(workspaceDir).map { x =>
      val svgFile = new File(workspaceDir, "iPath3.svg")
      Utils.svg2png(svgFile)
      super.resultDeal(workspaceDir, resultDir)
    }
    Utils.execFuture(f)
  }

  def stepIPath(workspaceDir: File)(implicit ws: WSClient, materializer: Materializer): Future[Unit] = {
    val startTime = System.currentTimeMillis()
    val nameFile = new File(workspaceDir, "name_map.txt")
    if (!nameFile.exists()) {
      return Future {
        println("error")
      }
    }
    val names = nameFile.lines.trimQuote.selectOneColumn("kegg").filter(_ != "NA").notEmptyLines
    if (names.size == 0) {
      return Future {
        println("error")
      }
    }
    val groupFile = new File(workspaceDir, "group.txt")
    val groupSize = groupFile.txtLines.selectOneColumn("classnote").distinct.notEmptyLines.size
    val fcFile = new File(workspaceDir, "fc_color.txt")
    val fcMap = fcFile.lines.lineMap.map { map =>
      val col = map("col")
      (map("kegg"), col)
    }.toMap
    val colorMap = fcMap.flatMap { case (keggId, col) =>
      val keggIds=keggId.mySplit("/")
      val webColor = col match {
        case "red" => "#FF0000"
        case "DeepSkyBlue" => "#00bfff"
        case "gold" => "#ffd700"
        case _ => ""
      }
      keggIds.map{keggId=>
        (keggId, webColor)
      }

    }
    val nameStr = names.map { x =>
      println(x)
      val webColor = colorMap(x)
      List(x, webColor, "W20").mkString("\t")
    }.mkString("\n")
    val mapData = Map(
      "selection" -> nameStr,
      "default_opacity" -> 1.toString,
      "default_width" -> 3.toString,
      "default_radius" -> 7.toString,
      "default_color" -> "#666666",
      "background_color" -> "#ffffff",
      "tax_filter" -> "",
      "export_type" -> "svg",
      "export_dpi" -> 1200.toString,
      "include_microbial" -> 0.toString,
      "whole_pathways" -> 0.toString,
      "include_secondary" -> 0.toString,
      "whole_modules" -> 0.toString,
      "include_antibiotic" -> 0.toString,
      "keep_colors" -> 1.toString,
      "include_metabolic" -> 1.toString,
      "query_reactions" -> 0.toString
    )
    ws.url("https://pathways.embl.de/mapping.cgi").withRequestTimeout(600 seconds).post(mapData).
      flatMap { response =>
        response.status match {
          case 200 => val file = new File(workspaceDir, "iPath3.svg")
            val outputStream = java.nio.file.Files.newOutputStream(file.toPath)
            val sink = Sink.foreach[ByteString] { bytes =>
              outputStream.write(bytes.toArray)
            }
            response.bodyAsSource.runWith(sink).andThen {
              case result =>
                outputStream.close()
                result.get
            }.map { x =>
              println(response)
              println(Utils.getTime(startTime))
            }
          case _ => Future {}
        }
      }.recover {
      case e: Exception =>
        e.printStackTrace()
        e.getMessage.toFile(new File(workspaceDir, "error.csv"))
    }

  }

  override def produceInput(workspaceDir: File, resultDir: File)(implicit dao: MyDao): Unit = {
    super.produceInput(workspaceDir, resultDir)
    val rawDataFile = new File(workspaceDir, "AllMet_Raw.txt")
    Tool.produceKeggInfoFile(rawDataFile, workspaceDir)
  }

  override def getCommandData(workspaceDir: File, resultDir: File, index: Int): List[CommandData] = {
    val solutionFile = new File(Tool.dataDir, "color_solution/color_solution_1.txt")
    val groupFile = new File(workspaceDir, "group.txt")
    val command =
      s"""
         |${Tool.rScript} ${new File(Tool.rPath, "anno.R").unixPath}
         |${"Rscript".condaPath()} ${new File(Tool.rPath, "idMapping.R").unixPath} --d ${Tool.databaseDir.unixPath}
           """.stripMargin
    List(CommandData(workspaceDir, List(command)))
  }

  override def getHtml(missionName: String, missionId: Option[Int])(implicit request: Request[AnyContent], messages: Messages): Html = {
    views.html.user.soft.iPath(missionName, missionId)
  }

  override def getMission(implicit request: Request[AnyContent], matrixFileDataDao: MatrixFileDataDao, messages: Messages, formBinding: FormBinding): Tables.MissionRow = {
    val input = if (data.hasGroup.isDefined) {
      List(data.file, data.groupFile)
    } else List(data.file)
    val hasLibInputs = input
    val argJson = getArg
    MissionRow(id = 0, missionName = s"${data.missionName}", kind = nameStr, userId = userId,
      startTime = new DateTime(), state = "preparing", arg = argJson, input = hasLibInputs)
  }

  override def produceInputFile(workspaceDir: File)(implicit request: Request[AnyContent], dao: MyDao, formBinding: FormBinding): Any = {
    val rawDataFile = new File(workspaceDir, "AllMet_Raw.txt")
    Tool.produceRawMetaboliteFile(userId, data.file, rawDataFile)
    val groupFile = new File(workspaceDir, "group.txt")
    if (data.hasGroup.isDefined) {
      Tool.produceRawGroupFile(userId, data.groupFile, rawDataFile, groupFile)
    } else {
      Tool.produceNoGroupFile(rawDataFile, groupFile)
    }
  }

  override def data(implicit request: Request[AnyContent], formBinding: FormBinding) = {
    FormTool.iPathForm.bindFromRequest().get
  }


}

